package io.gitee.kotle.android.library.crash

import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.text.Html
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.database.getStringOrNull
import androidx.fragment.app.Fragment
import io.gitee.kotle.android.R
import io.gitee.kotle.android.utils.*
import java.io.PrintWriter
import java.io.StringWriter
import java.lang.reflect.Field
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.HashMap

/**
 * 捕获全局异常
 */
class UncaughtExceptionFragment : Fragment() {
    companion object {
        private const val KEY_INFO = "errorInfo"
        fun start(context: Context, t: Thread, e: Throwable) {
            context.startFragment<UncaughtExceptionFragment> {
                it.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
                it.putExtra(KEY_INFO, getErrorInfo(context, e))
                context.startActivity(it)
            }
        }

        private fun getErrorInfo(context: Context, e: Throwable): String {
            //用于存储设备信息
            val mInfo: MutableMap<String, String> = HashMap()
            val pm: PackageManager = context.packageManager
            val info: PackageInfo =
                pm.getPackageInfo(context.packageName, PackageManager.GET_ACTIVITIES)
            // 获取版本信息
            val versionName =
                if (TextUtils.isEmpty(info.versionName)) "未设置版本名称" else info.versionName
            val versionCode = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                info.longVersionCode.toString() + ""
            } else {
                info.versionCode.toString() + ""
            }
            mInfo["versionName"] = versionName
            mInfo["versionCode"] = versionCode
            // 获取设备信息
            val fields: Array<Field> = Build::class.java.fields
            if (fields.isNotEmpty()) {
                for (field in fields) {
                    field.isAccessible = true
                    mInfo[field.name] = field.get(null).toString()
                }
            }
            return getErrorStackTrace(mInfo, e)
        }

        private fun getErrorStackTrace(mInfo: MutableMap<String, String>, e: Throwable): String {
            val stringBuffer = StringBuffer()
            stringBuffer.append(
                "${
                    longTimeToStr(
                        System.currentTimeMillis(),
                        "yyyy年MM月dd HH:mm:ss"
                    )
                }<br><br>"
            )
            stringBuffer.append("------------错误堆栈信息---------<br>")
            val stringWriter = StringWriter()
            val writer = PrintWriter(stringWriter)
            e.printStackTrace(writer)
            var cause = e.cause
            while (cause != null) {
                cause.printStackTrace(writer)
                val nextCause = e.cause
                cause = if (nextCause != cause) {
                    nextCause
                } else {
                    null
                }
            }
            writer.close()
            val string: String = stringWriter.toString()
            stringBuffer.append(string)
            stringBuffer.append("<br><br>------------设备信息---------<br>")
            for ((keyName, value) in mInfo) {
                stringBuffer.append("<b>$keyName：</b>$value<br>")
            }
            return stringBuffer.toString()
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_uncaught_exception, container, false)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val window = appCompatActivity.window
        window.statusBarColor = Color.parseColor("#333333")
        window.navigationBarColor = Color.parseColor("#333333")
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val errorInfo = Html.fromHtml(
            appCompatActivity.intent.getStringExtra(KEY_INFO)
        )
        view.findViewById<TextView>(R.id.tvInfo).text = errorInfo
        view.findViewById<View>(R.id.btReStart).setOnClickListener {
            getAppIntent()?.component?.className?.let {
                appCompatActivity.startActivity(Intent(appCompatActivity, Class.forName(it)))
                appCompatActivity.finish()
            }
        }
        saveLog(view.findViewById(R.id.btSave), errorInfo.toString())
    }

    private fun saveLog(it: TextView, errorInfo: String) {
        it.setOnClickListener { _ ->
            if (ContextCompat.checkSelfPermission(
                    appCompatActivity,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                ) ==
                PackageManager.PERMISSION_GRANTED
            ) {
                ActivityCompat.requestPermissions(
                    appCompatActivity,
                    arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                    1
                )
                return@setOnClickListener
            }
            it.isEnabled = false
            //格式化时间，作为Log文件名
            val dateFormat: DateFormat =
                SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒", Locale.getDefault())

            val uri = saveByteArrayToPublicDirectory(
                errorInfo.toByteArray(),
                SaveFileType.Download,
                "text/plain",
                "${dateFormat.format(Date())}.txt",
                "${SaveFileType.Download.path}/崩溃日志"
            )
            it.isEnabled = true
            if (uri != null) {
                Toast.makeText(appCompatActivity, "日志保存成功", Toast.LENGTH_SHORT).show()
                it.text = "第三方应用打开"
                it.setOnClickListener {
                    ignoreError {
                        val coursor =
                            appCompatActivity.contentResolver.query(uri, null, null, null, null)
                        if (coursor?.moveToFirst() == true) {
                            var path =
                                coursor.getStringOrNull(coursor.getColumnIndex(MediaStore.Files.FileColumns.DATA))
                            if (path.isNullOrBlank()) {
                                path =
                                    coursor.getStringOrNull(coursor.getColumnIndex(MediaStore.Downloads.RELATIVE_PATH))
                            }
                            if (!path.isNullOrBlank()) {
                                appCompatActivity.openFileByOtherApp(path)
                            }
                        }
                        coursor?.close()
                    }
                }
            } else {
                Toast.makeText(appCompatActivity, "日志保存失败", Toast.LENGTH_SHORT).show()
            }
        }
    }
}